package cn.ac.iie.di.ban.ycl.cleaner.common;

import cn.ac.iie.di.ban.ycl.cleaner.common.Constants;
import cn.ac.iie.di.datadock.rdata.exchange.client.core.REFieldType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.ahocorasick.trie.Emit;
import org.ahocorasick.trie.Trie;
import org.apache.commons.configuration2.Configuration;
import org.apache.commons.lang.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author zmc <zhangmingcheng@iie.ac.cn>
 * @date 2016-9-8 15:41:22
 * @version V1.0
 * @desc 封装数据类
 */
public class MyMessage {

    final Logger LOG = LoggerFactory.getLogger(MyMessage.class);
    private final String[] columnNames;
    private final REFieldType[] types;
    private final String docSchemaName;
    private final Map<String, String> userDesc;
    private List<Object[]> datas = new ArrayList<>();
    private final List<Object[]> garbageDatas = new ArrayList<>();
    private final List<Object> distinctFields;
    private final boolean isNeedDistinct;
    private final List<Object> filterKeyWords;
    private final int filterContentSize;

    public MyMessage(String[] columnNames,
            REFieldType[] types, String docSchemaName,
            Map<String, String> userDesc, List<Object[]> datas, Configuration configuration) {
        this.columnNames = columnNames;
        this.types = types;
        this.docSchemaName = docSchemaName;
        this.userDesc = userDesc;
        this.datas.addAll(datas);

        this.distinctFields = configuration.getList(Constants.DEDUPLICATION_FIELDS);
        this.isNeedDistinct = configuration.getBoolean(Constants.DEDUPLICATION_NECESSARY);
        this.filterKeyWords = configuration.getList(Constants.FILTER_CONTENT_KEYWORDS);//关键词列表
        this.filterContentSize = configuration.getInt(Constants.FILTER_CONTENT_SIZE);//内容长度

        LOG.debug("filter content keywords:{}", ArrayUtils.toString(this.filterKeyWords));
        LOG.debug("filter content size:{}", this.filterContentSize);
        LOG.debug("distinct fields:{}", ArrayUtils.toString(this.distinctFields));
        LOG.debug("need distinct:{}", isNeedDistinct);
    }

    /**
     * 过滤规则：cont字段对应的文本内容长度如果小于等于50，就与配置的关键词列表匹配，命中则为有效数据； 反之长度大于50，则为命中数据；
     * 包含图片数据的则为命中数据
     */
    public void filter() throws Exception {
        List<Object[]> newMessage = new ArrayList<>();

        List<String> columnList = Arrays.asList(columnNames);
        int wxauIndex = columnList.indexOf("wx_au");
        if (wxauIndex < 0) {
            throw new Exception("wx_au field does not exists! " + ArrayUtils.toString(columnList));
        }
        int contIndex = columnList.indexOf("cont");
        if (contIndex < 0) {
            throw new Exception("cont field does not exists! " + ArrayUtils.toString(columnList));
        }
        int wxSfromIndex = columnList.indexOf("wx_sfrom");
        if (wxSfromIndex < 0) {
            throw new Exception("wx_sfrom field does not exists! " + ArrayUtils.toString(columnList));
        }

        Trie trie = new Trie();
        for (Iterator<Object> it = filterKeyWords.iterator(); it.hasNext();) {
            String keyword = (String) it.next();
            String keywordUnicode = chToUnicode(keyword);
            trie.addKeyword(keywordUnicode);
        }
        for (Object[] data : this.datas) {
            //推送消息无ID
            String wxSfrom = (String) data[wxSfromIndex];
            if (wxSfrom == null || wxSfrom.isEmpty()) {
//                LOG.warn("the value of cont field  is null or empty!");
                garbageDatas.add(data);
                continue;
            }
            //包含图片
            String[] wxauContent = (String[]) data[wxauIndex];
            if (wxauContent.length == 1 && wxauContent[0].isEmpty()) {
//                LOG.warn("the value of wxau field  is null or empty!");
            } else {
                LOG.debug("wx_au:" + Arrays.toString(wxauContent));
                newMessage.add(data);
                continue;
            }

            String content = (String) data[contIndex];
            if (content == null || content.isEmpty()) {
//                LOG.warn("the value of cont field  is null or empty!");
                garbageDatas.add(data);
            } else if (content.length() <= this.filterContentSize) { //字符串长度《=50,匹配关键词
                Collection<Emit> emits = trie.parseText(chToUnicode(content));
                if (!emits.isEmpty() && emits.size() > 0) {
                    newMessage.add(data);
                } else {
                    garbageDatas.add(data);
                }
            } else {//字符串长度>50
                newMessage.add(data);
            }
        }
        this.datas = newMessage;
    }

    private String chToUnicode(String content) {
        char[] utfBytes = content.toCharArray();
        String unicodeBytes = "";
        for (int byteIndex = 0; byteIndex < utfBytes.length; byteIndex++) {
            String hexB = Integer.toHexString(utfBytes[byteIndex]);
            if (hexB.length() <= 2) {
                hexB = "00" + hexB;
            }
            unicodeBytes = unicodeBytes + "\\u" + hexB;
        }
        return unicodeBytes;
    }

    public String[] getColumnNames() {
        return columnNames;
    }

    public REFieldType[] getTypes() {
        return types;
    }

    public int getMessagSize() {
        return this.datas.size();
    }

    public String getDocSchemaName() {
        return docSchemaName;
    }

    public Map<String, String> getUserDesc() {
        return userDesc;
    }

    public List<Object[]> getData() {
        return datas;
    }

    //获取需要去重 的字段值
    public String getDeduplicationValues() {
        StringBuilder sb = new StringBuilder();
        List<String> columnList = Arrays.asList(columnNames);
        for (Object[] data : this.datas) {
            boolean isFirst = true;
            for (Iterator<Object> it = distinctFields.iterator(); it.hasNext();) {
                String distinctField = (String) it.next();
                int index = columnList.indexOf(distinctField);
                if (index < 0) {
                    LOG.info(distinctField);
                    LOG.error("the distinct field: {} does not exists!", distinctField);
                }
                Object distinctFieldValue = data[index];
                if (distinctFieldValue == null || distinctFieldValue.toString().isEmpty()) {
                    LOG.info("columnames:{}", Arrays.toString(columnNames));
                    LOG.info("data:{}", Arrays.toString(data));
                    LOG.error("the value of distinct field: {} is null or empty!", distinctField);
                }
                if (!isFirst) {
                    sb.append("^");
                }
                sb.append(distinctFieldValue);
                isFirst = false;
            }
            sb.append("\n");
        }
        return sb.toString();
    }

    public void distinct(List<String> flags) {
        List<Object[]> newMessage = new ArrayList<>();
        for (int i = 0; i < flags.size(); i++) {
            if (flags.get(i).equals("0")) {
                newMessage.add(datas.get(i));
            }
        }
        this.datas = newMessage;
    }

    public SendObject getSendObj() {
        SendObject sendObject
                = new SendObject(columnNames, types, docSchemaName, userDesc, datas);
        return sendObject;
    }

    public SendObject getGarbageSendObj() {
        SendObject sendObject
                = new SendObject(columnNames, types, docSchemaName, userDesc, garbageDatas);
        return sendObject;
    }
}
